/**
 * 
 */
package br.org.bertol.mestrado.engine;

import java.io.FileOutputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.CountDownLatch;

import org.apache.log4j.Logger;
import org.apache.poi.ss.usermodel.Workbook;

import br.org.bertol.mestrado.engine.exception.HeuristicsException;
import br.org.bertol.mestrado.engine.fitness.AbstractCombinatorialFitness;
import br.org.bertol.mestrado.engine.fitness.MutantAnalysis;
import br.org.bertol.mestrado.engine.fitness.Objective;
import br.org.bertol.mestrado.engine.optimisation.aco.AntColonyOptimization;
import br.org.bertol.mestrado.engine.optimisation.entity.Ant;
import br.org.bertol.mestrado.engine.optimisation.moo.OrdenatePareto;
import br.org.bertol.mestrado.engine.optimisation.moo.ParetoMinMinDominace;
import br.org.bertol.mestrado.util.AntConfiguration;

/**
 * @author contaqualquer
 */
public class EngineAnt extends AbstractSearchEngine<String> {

    /***/
    private final transient AntConfiguration                    antConfiguration;

    /***/
    private final transient List<AntColonyOptimization<String>> resultAnt;

    /**
     * @param startS
     * @param stopS
     * @param objectives
     * @param storeP
     * @param sID
     * @param configuration
     */
    public EngineAnt(final CountDownLatch startS, final CountDownLatch stopS,
        final Objective[] objectives, final String storeP, final String sID,
        final AntConfiguration configuration) {

        super(startS, stopS, configuration.getIteracoes(), storeP, sID,
                objectives);

        antConfiguration = configuration;

        resultAnt = new ArrayList<AntColonyOptimization<String>>();

    }

    @Override
    public final void run() {
        try {
            // deixa sistema ponto para entrar em ação
            startSystem.await();

            final ArrayList<String> starterClasses = randomSolution
                    .getStarterClasses(antConfiguration.getUsage(),
                                       antConfiguration.getSidePopulation());

            if (verify.isSystemEnable()) {
                Logger.getLogger(this.getClass()).info(systemID + " Start");

                final List<Ant<String>> ants = new ArrayList<Ant<String>>();

                // cria lista de ants
                for (int i = 0; i < starterClasses.size(); i++) {

                    final AbstractCombinatorialFitness<String> mutantAnalysis = new MutantAnalysis(
                            (ArrayList<String>) verify.getClasses(), 0.4);

                    final Ant<String> formiga = new Ant<String>(
                            antConfiguration.getAlpha(), antConfiguration
                            .getBeta(),
                            antConfiguration.getWellThreshold(),
                            mutantAnalysis, verify.getObjectives());

                    ants.add(formiga);
                }

                // cria colônia de formigas
                final AntColonyOptimization<String> colonyOptimization =
                        new AntColonyOptimization<String>(numIteracoes,
                        ants, antConfiguration.getEvaporation(),
                        antConfiguration.getMinpheromone(),
                        starterClasses,
                        (ArrayList<String>) verify.getClasses(), verify
                        .getObjectives());

                initTime = System.currentTimeMillis();

                colonyOptimization.evaluate();

                stopTime = System.currentTimeMillis();

                resultAnt.add(colonyOptimization);

                final List<Ant<String>> list = colonyOptimization
                        .getParetoBorder();

                Collections.sort(list, new OrdenatePareto<Ant<String>>(
                        new ParetoMinMinDominace()));

                // informações adicionais

                final HashMap<String, Number> hashMap =
                        new HashMap<String, Number>();

                hashMap.put("Nº de iterações", numIteracoes);
                hashMap.put("Taxa de evaporação", antConfiguration
                        .getEvaporation());
                hashMap.put("Taxa min. fer.", antConfiguration
                        .getMinpheromone());
                hashMap.put("Fator alpha", antConfiguration.getAlpha());
                hashMap.put("Fator beta", antConfiguration.getBeta());

                consolidateResult(list, hashMap);

                final String fileNameTXT = new String(storePath + "/"
                        + systemID
                        + "/resultado_avaliacao_" + systemID + "_ACO.txt");

                final String fileNameXLS = new String(storePath + "/"
                        + systemID
                        + "/resultado_avaliacao_" + systemID + "_ACO.xls");

                final Workbook workbook = getInputStream(fileNameXLS);

                storeResultXls(workbook);

                storeResultTxt(fileNameTXT);

                final FileOutputStream out = new FileOutputStream(fileNameXLS);

                workbook.write(out);

                out.close();

                Logger.getLogger(this.getClass()).info(systemID + " End");
            }
        } catch (InterruptedException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (IOException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        } catch (HeuristicsException e) {
            Logger.getLogger(this.getClass()).error(
                                                    "Erro ao executar sistema "
                    + systemID, e);
        }

        // notifica main thread
        stopSystem.countDown();
    }
}
